﻿#include <mzfc_inc.h>
#include "HexagonMineCanvas.h"

CHexagonMineCanvas::CHexagonMineCanvas()
{
	m_CenterWidth = 50;
	m_CenterHeight = int(m_CenterWidth * 0.866);

	m_HoleRadius = (m_CenterWidth - m_CenterHeight / 20) / 2;

	X_ADJUST = 2;
	Y_ADJUST = 2 + (m_CenterWidth - m_CenterHeight) / 2;

	m_DownHoleX = -1;
	m_DownHoleY = -1;
	m_DownTick = 0;

	m_Game = 0;
}

CHexagonMineCanvas::~CHexagonMineCanvas()
{
}

void CHexagonMineCanvas::Init(hexagon_mine::CHexagonMineGame* game)
{
	if (m_dcCanvas.GetDC()==0)
	{
		m_dcCanvas.Create(GetWidth(), GetHeight());
	}

	m_Game = game;
}

void CHexagonMineCanvas::DrawHole(int hexagon_x, int hexagon_y, int value, hexagon_mine::HOLE_STATUS status)
{
	int x_center, y_center;
	GetHexagonHoleCenter(hexagon_x, hexagon_y, x_center, y_center);

	RECT rc = {x_center - m_HoleRadius, y_center - m_HoleRadius,
		x_center + m_HoleRadius, y_center + m_HoleRadius};

	HPEN pen = ::CreatePen(PS_SOLID, 3, RGB(128, 128, 128));
	HGDIOBJ old = SelectObject(m_dcCanvas.GetDC(), pen);
	::Ellipse(m_dcCanvas.GetDC(), rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1);
	DeleteObject(SelectObject(m_dcCanvas.GetDC(), old));

	if (status != hexagon_mine::HMHS_OPEN)
	{
		COLORREF bg_color = ::MzGetThemeColor(TCI_CAPTION_BG2);
		if ((hexagon_x == m_DownHoleX) && (hexagon_y == m_DownHoleY))
		{
			DWORD t = GetTickCount() - m_DownTick;
			if (t > 200)
				bg_color = RGB(0, 255, 0);
		}

		HBRUSH brush = ::CreateSolidBrush(bg_color);
		HGDIOBJ old = SelectObject(m_dcCanvas.GetDC(), brush);
		::Ellipse(m_dcCanvas.GetDC(), rc.left + 1, rc.top + 1, rc.right - 1, rc.bottom - 1);
		DeleteObject(SelectObject(m_dcCanvas.GetDC(), old));

		DrawSign(status, rc);
		return;
	}

	::Ellipse(m_dcCanvas.GetDC(), rc.left + 1, rc.top + 1, rc.right, rc.bottom);

	const wchar_t numbers[] = {L'　', L'１', L'２', L'３', L'４', L'５', L'６'};
	wchar_t symbol[2] = {0};
	symbol[0] = numbers[value];
	
	int font_radius = m_HoleRadius * 6 / 10;
	rc.left = x_center - font_radius;
	rc.top = y_center - font_radius;
	rc.right = x_center + font_radius;
	rc.bottom = y_center + font_radius;

	HFONT font = FontHelper::GetFont(font_radius * 2, FW_EXTRABOLD);
	HGDIOBJ oldf = SelectObject(m_dcCanvas.GetDC(), font);
	::MzDrawText(m_dcCanvas.GetDC(), symbol, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
	SelectObject(m_dcCanvas.GetDC(), oldf);
}

void CHexagonMineCanvas::DrawSign(hexagon_mine::HOLE_STATUS status, RECT rc)
{
	int x_center = (rc.left + rc.right) / 2;
	int y_center = (rc.top + rc.bottom) / 2;

	int radius = m_HoleRadius;

	switch (status)
	{
	case hexagon_mine::HMHS_COVER:
		break;
	case hexagon_mine::HMHS_MARK:
		{
			int x1 = x_center - radius * 6 / 10;
			int y1 = y_center + radius * 1 / 10;

			int x2 = x_center + radius * 3 / 10;
			int y2 = y_center - radius * 7 / 10;

			int x3 = x_center + radius * 2 / 10;
			int y3 = y_center;

			int x4 = x_center + radius * 1 / 10;
			int y4 = y_center + radius * 7 / 10;

			POINT pts[] = 
			{
				{x1, y1},
				{x2, y2}, 
				{x3, y3},
				{x1, y1},
			};
			HBRUSH brush = ::CreateSolidBrush(RGB(255, 0, 0));
			HGDIOBJ old = SelectObject(m_dcCanvas.GetDC(), brush);
			Polygon(m_dcCanvas.GetDC(), pts, 4);
			DeleteObject(SelectObject(m_dcCanvas.GetDC(), old));

			::MoveToEx(m_dcCanvas.GetDC(), x3, y3, 0);
			::LineTo(m_dcCanvas.GetDC(), x4, y4);
			//::Rectangle(m_dcCanvas.GetDC(), h_mid - 1, v_mid, h_mid, bottom);
		}
		break;
	case hexagon_mine::HMHS_QUESTION:
		{
		}
		break;
	case hexagon_mine::HMHS_BOMB:
		{
			{
				int rx = x_center - radius * 6 * 707 / 10 / 1000;
				int ry = y_center - radius * 6 * 707 / 10 / 1000;

				int r30 = radius * 6 / 10 / 2;
				int r60 = radius * 6 * 433 / 10 / 500;

				int d1 = (x_center + radius / 10 - r30) - rx;
				int d2 = (y_center + radius / 10 - r60) - ry;

				POINT pts[] = 
				{
					{rx - d1, ry + d2},
					{rx - d2, ry + d1}, 
					{rx + d1, ry - d2},
					{rx + d2, ry - d1},
					{rx - d1, ry + d2},
				};

				HBRUSH brush = ::CreateSolidBrush(RGB(32, 32, 32));
				HGDIOBJ old = SelectObject(m_dcCanvas.GetDC(), brush);
				::Polygon(m_dcCanvas.GetDC(), pts, 5);
				DeleteObject(SelectObject(m_dcCanvas.GetDC(), old));
			}

			{
				int cx = x_center + radius * 1 / 10;
				int cy = y_center + radius * 1 / 10;
				int r = radius * 6 / 10;

				HPEN pen =::CreatePen(PS_SOLID, 1, RGB(128, 128, 128));
				HGDIOBJ oldp = SelectObject(m_dcCanvas.GetDC(), pen);
				HBRUSH brush = ::CreateSolidBrush(RGB(0, 0, 0));
				HGDIOBJ old = SelectObject(m_dcCanvas.GetDC(), brush);
				::Ellipse(m_dcCanvas.GetDC(), cx - r, cy - r, cx + r, cy + r);
				DeleteObject(SelectObject(m_dcCanvas.GetDC(), old));
				DeleteObject(SelectObject(m_dcCanvas.GetDC(), oldp));
			}
		}
		break;
	case hexagon_mine::HMHS_BROKEN:
		{
			POINT org[] =
			{
				{-5,  1},
				{-8, -3},
				{-3, -3},
				{-3, -8},
				{-1, -4},
				{ 3, -8},
				{ 2, -3},
				{ 7, -4},
				{ 2,  0},
				{ 7,  4},
				{ 1,  3},
				{ 3,  8},
				{-1,  4},
				{-3,  8},
				{-3,  3},
				{-8,  4},
			};

			POINT pts[17];

			for (int i = 0; i < 17; ++i)
			{
				int ii = i % 16;
				pts[i].x = x_center + radius * org[ii].x / 10;
				pts[i].y = y_center + radius * org[ii].y / 10;
			};

			HBRUSH brush = ::CreateSolidBrush(RGB(255, 255, 0));
			HGDIOBJ old = SelectObject(m_dcCanvas.GetDC(), brush);
			Polygon(m_dcCanvas.GetDC(), pts, 17);
			DeleteObject(SelectObject(m_dcCanvas.GetDC(), old));
		}
		break;
	}
}

void CHexagonMineCanvas::Init(int num_width, int num_height, bool horizontal, bool left_side, bool right_side)
{
	int total_width = GetWidth();
	int total_height = GetHeight();

	int cw_by_width = total_width * 2 / ((num_width - 1 + left_side) * 2 + right_side);
	int cw_by_height = total_height / (num_height + 0.1547) * 1.1547;

	m_CenterWidth = (cw_by_width < cw_by_height) ? cw_by_width : cw_by_height;
	m_CenterHeight = int(m_CenterWidth * 0.866);

	m_HoleRadius = (m_CenterWidth - m_CenterHeight / 20) / 2;

	X_ADJUST = (total_width - m_CenterWidth * num_width - right_side * m_CenterWidth / 2 ) / 2;
	Y_ADJUST = (total_height - m_CenterHeight * num_height) / 2;

	m_DownHoleX = -1;
	m_DownHoleY = -1;
	m_DownTick = 0;

	RECT rc = GetClientRect();
	HBRUSH hBrush = CreateSolidBrush(::MzGetThemeColor(TCI_CAPTION_BG1));
	FillRect(m_dcCanvas.GetDC(), &rc, hBrush);
	DeleteObject(hBrush);

	DrawFocusRect(m_dcCanvas.GetDC(), &rc);

	Invalidate();
}

void CHexagonMineCanvas::Update(const std::vector<hexagon_mine::IGameShowObserver::HoleInfo>& holes)
{
	for (size_t i = 0; i < holes.size(); ++i)
	{
		hexagon_mine::IGameShowObserver::HoleInfo info = holes[i];
		DrawHole(info.x, info.y, info.value, info.status);
	}

	Invalidate();
}

bool CHexagonMineCanvas::ConvertXYToHexagon(int x, int y, int& hexagon_x, int& hexagon_y) const
{
	int h_y = (y - Y_ADJUST) / m_CenterHeight;
	int h_x = (x - X_ADJUST - h_y % 2 * m_CenterWidth / 2) / m_CenterWidth;

	hexagon_x = h_x;
	hexagon_y = h_y;

	int xc, yc;
	GetHexagonHoleCenter(h_x, h_y, xc, yc);

	int r = m_HoleRadius * 8 / 10;
	int dx = x - xc;
	int dy = y - yc;

	if (dx * dx + dy * dy > r * r)
		return false;

	return true;
}

void CHexagonMineCanvas::GetHexagonHoleCenter(int hexagon_x, int hexagon_y, int& x, int& y) const
{
	x = m_CenterWidth / 2 + X_ADJUST + hexagon_x * m_CenterWidth + hexagon_y % 2 * m_CenterWidth / 2;
	y = m_CenterHeight / 2 + Y_ADJUST + hexagon_y * m_CenterHeight;
}

bool CHexagonMineCanvas::SetDownHexagonXY(int x, int y)
{
	bool changed = false;

	if (m_DownHoleX != -1)
	{
		if ((m_DownHoleX == x) && (m_DownHoleY == y))
		{
			UpdateHole(x, y);
			return true;
		}

		int dx = m_DownHoleX;
		int dy = m_DownHoleY;
		
		m_DownHoleX = -1;
		m_DownHoleY = -1;
		m_DownTick = 0;

		UpdateHole(dx, dy);

		changed = true;
	}

	if (x != -1)
	{
		m_DownHoleX = x;
		m_DownHoleY = y;
		m_DownTick = GetTickCount();
		
		// 不要立即更新，等到界面主动更新
		//UpdateHole(x, y);

		changed = true;
	}

	return changed;
}

void CHexagonMineCanvas::UpdateDownHole()
{
	UpdateHole(m_DownHoleX, m_DownHoleY);
}

void CHexagonMineCanvas::UpdateHole(int hexagon_x, int hexagon_y)
{
	int value;
	hexagon_mine::HOLE_STATUS status;
	if (m_Game->QueryHoleShowStatus(hexagon_x, hexagon_y, value, status))
	{
		DrawHole(hexagon_x, hexagon_y, value, status);

		int x, y;
		GetHexagonHoleCenter(hexagon_x, hexagon_y, x, y);
		RECT rc = {x - m_CenterWidth, y - m_CenterHeight, x + m_CenterWidth, y + m_CenterHeight};
		Invalidate(&rc);
	}
}
